#include <linux/kernel.h>
#include <linux/module.h>
#include <net/inet_hashtables.h>
#include <net/tcp.h>
#include <linux/inet.h>
#include <net/inet_common.h>
#include <net/route.h>
#include <net/ip6_route.h>

#include "tcp_hack.h"

char http[2048] = {0};
char g_local_interface[40];  //"eth0"
char g_mirror_interface[40]; //"eth1"
enum family_type {
	FAMILY_INVALID = -1,
	IPV4 = 0,
	IPV6 = 1,
	FAMILY_NUM,
};

int change_destination4(struct sk_buff *skb, struct in_addr *daddr)
{
	struct rtable *rt;                      /* Route to the other host */
	struct flowi4 fl4;
	struct iphdr  *iph = ip_hdr(skb);
	struct net *net;

	if (!skb_dst(skb)) {
		if (!skb->dev) {
			net = &init_net;
		} else {
			net = dev_net(skb->dev);
		}
	} else {
		net = dev_net(skb_dst(skb)->dev);
	}

	memset(&fl4, 0, sizeof(fl4));
	fl4.daddr = (*(__be32 *)daddr);
	fl4.flowi4_tos =  RT_TOS(iph->tos);
	fl4.flowi4_flags = FLOWI_FLAG_KNOWN_NH;
	rt = ip_route_output_key(net, &fl4);

	if (!rt) {
		goto tx_error_icmp;
	}

	/* MTU checking */
	/*mtu = dst_mtu(&rt->dst);
	if ((iph->frag_off & htons(IP_DF)) && skb->len > mtu &&
	    !skb_is_gso(skb)) {
	        icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
	        goto tx_error;
	}*/
	/* drop old route */
	ip_send_check(ip_hdr(skb));
	skb_dst_drop(skb);
	skb_dst_set(skb, &rt->dst);
	/* Another hack: avoid icmp_send in ip_fragment */
	return 0;
tx_error_icmp:
	dst_link_failure(skb);
//tx_error:
	kfree_skb(skb);
	return -1;
}
int change_destination6(struct sk_buff *skb, struct in6_addr *daddr)
{
	struct flowi6 fl6 ;
	struct net *net;
	struct rt6_info *rt;
	struct dst_entry *dst;

	if (!skb_dst(skb)) {
		if (!skb->dev) {
			net = &init_net;
		} else {
			net = dev_net(skb->dev);
		}
	} else {
		net = dev_net(skb_dst(skb)->dev);
	}

	fl6.daddr = *daddr;
	dst = ip6_route_output(net, NULL, &fl6);

	if (!dst) {
		goto tx_error_icmp;
	}

	rt = (struct rt6_info *)dst;
	skb = skb_share_check(skb, GFP_ATOMIC);

	if (unlikely(skb == NULL)) {
		dst_release(dst);
		return -1;
	}

	/* drop old route */
	skb_dst_drop(skb);
	skb_dst_set(skb, &rt->dst);
	return 0;
tx_error_icmp:
	dst_link_failure(skb);
//tx_error:
	kfree_skb(skb);
	return -1;
}

int packet_send(int family, struct sk_buff *skb)
{
	int pf;
	int err;

	if (family == IPV4) {
		pf = AF_INET;
	} else {
		pf = AF_INET6;
	}

	skb_forward_csum(skb);
	//NF_HOOK(pf, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev,dst_output);
	err = dst_output(skb);

	if (err) {
		//log_err(ERR_SOCKET, "packet forward failed");
		//kfree_skb(skb); //mem dst_output(skb); release by manual
		//0630 remove first, it seems make error
	} else {
	}

	return 0; //mem be careful , outside call should return NF_STOLEN
}

unsigned int process_pre_routing(struct sk_buff *skb,const struct net_device *in, const struct net_device *out)
{
	//非镜像网口数据不用处理
	if( 0 != memcmp(in->name, g_mirror_interface, strlen(g_mirror_interface)))
		return NF_ACCEPT;

	printk("******[%s]   protocol:%d   dst:%pI4   src:%pI4  dport:%d   sport:%d   pkt_type:%d   indev:%s ******\n", __FUNCTION__, ip_hdr(skb)->protocol,&ip_hdr(skb)->daddr, &ip_hdr(skb)->saddr, ntohs(tcp_hdr(skb)->dest),ntohs(tcp_hdr(skb)->source),skb->pkt_type,in->name);
	if(ip_hdr(skb)->protocol == IPPROTO_TCP && ntohs(tcp_hdr(skb)->dest) == 80 )
			//&& tcp_hdr(skb)->syn != 1)
	{}
	else
		goto drop;


    struct in_addr to_ipv4;
    char *p = &to_ipv4;
    *p = 10;
    p++;
    *p = 2;
    p++;
    *p = 1;
    p++;
    *p = 56;
    printk("to_ipv4 addr[%pI4]\n", &to_ipv4);
    //change_destination4(skb, &to_ipv4);
    if (change_destination4(skb, &to_ipv4)) {
        printk("process_pre_routing 4\n");
        return NF_DROP;
    }
    if (packet_send(IPV4, skb)) {
        printk("process_pre_routing 8\n");
        return NF_DROP;
    } else {
        printk("process_pre_routing 9\n");
        return NF_STOLEN;
    }


accept:
drop:
	return NF_ACCEPT;
}

unsigned int process_pre_routing_v6(struct sk_buff *skb,const struct net_device *in, const struct net_device *out)
{
    //非镜像网口数据不用处理
    if( 0 != memcmp(in->name, g_mirror_interface, strlen(g_mirror_interface)))
        return NF_ACCEPT;
    struct ipv6hdr *ip6_header;
    struct in6_addr saddr, daddr;
    ip6_header = ipv6_hdr(skb);
    daddr = ip6_header->daddr;
    saddr = ip6_header->saddr;

    printk("=======process_pre_routing_v6, ip6_header, saddr[%pI6c] daddr[%pI6c] pkt_type:%d\n", &saddr, &daddr, skb->pkt_type);
    //KDEBUG("******[%s]   protocol:%d   dst:%pI4   src:%pI4  dport:%d   sport:%d   pkt_type:%d   indev:%s ******\n", __FUNCTION__, ip_hdr(skb)->protocol,&ip_hdr(skb)->daddr, &ip_hdr(skb)->saddr, ntohs(tcp_hdr(skb)->dest),ntohs(tcp_hdr(skb)->source),skb->pkt_type,in->name);
    if(ipv6_hdr(skb)->nexthdr == NEXTHDR_TCP && ntohs(tcp_hdr(skb)->dest) == 80 )
        //&& tcp_hdr(skb)->syn != 1)
    {}
    else
        goto drop;


    skb->pkt_type = PACKET_HOST;
    struct in6_addr to_ipv6;
    char *p = &to_ipv6;
    *p = 0x20;
    p++;
    *p = 01;
    p++;
    *p = 00;
    p++;
    *p = 0x10;
    p++;
    *p = 00;
    p++;
    *p = 02;
    p++;
    *p = 00;
    p++;
    *p = 01;
    p++;

    *p = 00;
    p++;
    *p = 00;
    p++;

    *p = 00;
    p++;
    *p = 00;
    p++;

    *p = 00;
    p++;
    *p = 00;
    p++;

    *p = 00;
    p++;
    *p = 0x56;
    //change_destination4(skb, &to_ipv4);
    printk("to_ipv6 addr[%pI6c]\n", &to_ipv6);
    if (change_destination6(skb, &to_ipv6)) {
        printk("process_pre_routing_v6 4\n");
        return NF_DROP;
    }
    if (packet_send(IPV6, skb)) {
        printk("process_pre_routing_v6 8\n");
        return NF_DROP;
    } else {
        printk("process_pre_routing_v6 9\n");
        return NF_STOLEN;
    }
    accept:
    drop:
    return NF_ACCEPT;
}

